﻿// Copyright (c) 2012 - 2020 Jared Zheng <jaredz at outlook dot com>
// Buddha Framework is licensed under Mulan PSL v2.
// You can use this software according to the terms and conditions of the Mulan PSL v2.
// You may obtain a copy of Mulan PSL v2 at:
//          http://license.coscl.org.cn/MulanPSL2
// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
// EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
// MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
// See the Mulan PSL v2 for more details.
//
// Create : 2012-12-01 version 0.1 Jared Zheng <jaredz at outlook dot com>
// Update : 2018-12-05 version 3.1.5 Jared Zheng <jaredz at outlook dot com>

#ifndef __MASTER_SERVER_IMP_H__
#define __MASTER_SERVER_IMP_H__

#pragma once

#include "commonpacket.h"
#include "CommonServer.h"
#include "CommonRoutine.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////
/// 业务管理服务器实现
class CMasterServer : public ICommonServer, public CPAKHandler
{
public:
    CMasterServer(void);
    virtual ~CMasterServer(void);
    // CComponent
    // Command to set param value
    virtual UInt   Command(PCXStr pszCMD, uintptr_t utParam) OVERRIDE;
    virtual UInt   Update(void) OVERRIDE;

    virtual UInt   Init(CEventHandler& EventHandlerRef, CServerConfig& ConfigRef) OVERRIDE;
    virtual void   Exit(void) OVERRIDE;

    virtual bool   Start(void) OVERRIDE;
    virtual bool   Pause(bool bPause = true) OVERRIDE;
    virtual void   Stop(void) OVERRIDE;
    // CPAKHandler
    virtual bool   OnTcpDispatch(const PacketPtr& PktPtr, PTCP_PARAM pTcp) OVERRIDE;
    virtual bool   OnUdpDispatch(const PacketPtr& PktPtr, PUDP_PARAM pUdp) OVERRIDE;
    virtual bool   OnTcpAccept(Socket sAccept, Socket sListen) OVERRIDE;
    virtual bool   OnTcpConnect(UInt uError, Socket sConnect) OVERRIDE;
    virtual bool   OnTcpRecv(size_t stSize, PTCP_PARAM pTcp) OVERRIDE;//
    virtual bool   OnTcpSend(UInt uQueueLimit, Socket sSocket) OVERRIDE;//
    virtual bool   OnTcpClose(Socket sSocket, ULLong ullLiveData) OVERRIDE;

    virtual bool   OnUdpRecv(size_t stSize, PUDP_PARAM pUdp) OVERRIDE;//
    virtual bool   OnUdpSend(UInt uQueueLimit, Socket sSocket) OVERRIDE;//
    virtual bool   OnUdpClose(Socket sSocket, ULLong ullLiveData) OVERRIDE;
    // Routine
    virtual Socket_t          GetSocket(UInt uType) OVERRIDE;
    virtual PSERVER_INFO      GetServerInfo(UInt uType) OVERRIDE;
    virtual PSVR_COMMON_MAP   GetServerMap(UInt uType) OVERRIDE;
    virtual PRESULT_CHAIN     GetServerSort(UInt uType) OVERRIDE;
    virtual CServerConfig&    GetConfig(void) OVERRIDE;
    virtual CFileLog&         GetFileLog(void) OVERRIDE;
    virtual CEventHandlerPtr& GetMgrHandler(void) OVERRIDE;
    virtual CNetworkPtr&      GetNetworkPtr(void) OVERRIDE;
private:
    CMasterServer(const CMasterServer&);
    CMasterServer& operator=(const CMasterServer&);
    /// 配置相关
    bool  LoadConfig(void);
    void  UnloadConfig(void);

    bool  StartConnectCenterServer(void);
    bool  StartConnectMasterDBServer(void);
    bool  StartListenAuthor(void);
    bool  StartListenInternal(void);

    bool  CheckConnectCenterServer(void);
    bool  CheckConnectMasterDBServer(void);
    bool  CheckListenAuthor(void);
    bool  CheckListenInternal(void);

    void  StopConnectCenterServer(void);
    void  StopConnectMasterDBServer(void);
    void  StopListenAuthor(void);
    void  StopListenInternal(void);

    /// 向同步管理服务器注册/注销
    void  LinkCenterServer(void);
    void  UnlinkCenterServer(void);
    /// 向授权数据服务器注册/注销
    void  LinkMasterDBServer(void);
    void  UnlinkMasterDBServer(void);

    /// 处理同步管理服务器的信令包
    bool  DispatchCenterServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp);
    /// 处理业务数据服务器的信令包
    bool  DispatchMasterDBServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp);
    /// 处理业务功能/网关服务器的信令包
    bool  DispatchMasterServer(const PacketPtr& PktPtr, PTCP_PARAM pTcp);

    /// 同步服务器信息给控制台
    bool  SyncServersInfo(void);
    /// 同步管理服务器信息给控制台
    bool  SyncMasterServerInfo(void);
    /// 同步业务功能服务器信息给控制台
    bool  SyncServiceServerInfo(void);
    /// 同步业务网关服务器负载情况并同步给控制台
    bool  SyncGateSortInfo(void);

    bool  OnServerLink(CNETLink* pLink, Socket sSocket);
    bool  OnServerUpdate(CNETUpdate* pUpdate, Socket sSocket);
    bool  OnServerUnlink(CPAKHeadBase* pUnlink, Socket sSocket, SERVER_UNLINK& su);
    /// 注册服务器数据
    template <typename MAP_REF, PAK_TYPE PakType>
    bool  ServerLink(CNETLink* pLink, ULLong ullKey, MAP_REF& MapRef);
    /// 更新服务器数据
    template <typename MAP_REF, PAK_TYPE PakType>
    bool  ServerUpdate(CNETUpdate* pUpdate, ULLong ullKey, MAP_REF& MapRef);
    /// 注销服务器数据
    template <typename MAP_REF, PAK_TYPE PakType>
    bool  ServerUnlink(Socket sSocket, MAP_REF& MapRef, SERVER_UNLINK& su);

    void  GetServerInfo(MASTER_ADDR& ServerInfo, UShort usStatus = STATUSU_SYNC);

    bool  LoadExtConfig(void);
    bool  LoadExtRoutine(CKVNode& Root);
    bool  CreateRTTIObject(PCXStr pszObject, PCXStr pszName, PCXStr pszModule);
    bool  UnloadExtConfig(void);
    bool  UnloadExtRoutine(void);
private:
    Int                     m_nStatus;          ///< 服务器状态
    Int                     m_nCenterLink;      ///< 连接同步管理服务器状态
    Int                     m_nMasterDBLink;    ///< 连接业务数据服务器状态
    // 框架例程开关, 由框架例程通过调用Command修改服务器实例对应参数
    Int                     m_nServerInfo;      ///< 例程需要处理服务器同步信息PAKE_LINK/PAKE_UPDATE/PAKE_UNLINK的SERVER_INFO
    Int                     m_nServerAck;       ///< 例程需要处理连接上服务器ACK信息PAKE_LINKACK/PAKE_UNLINKACK
    Int                     m_nSyncInfo;        ///< 例程需要处理服务器PAKE_LINK/PAKE_UPDATE同步信息时增加其他数据
    Int                     m_nCommonEvent;     ///< 例程需要处理服务器内部通用PAKE_COMMON_BEGIN/PAKE_COMMON_END事件
    //
    CServerConfig*          m_pConfig;          ///< 配置
    Socket                  m_sConnectCenter;   ///< 内网, 连接同步管理服务器
    Socket                  m_sConnectMasterDB; ///< 内网, 连接业务数据服务器
    Socket                  m_sListenAuthor;    ///< 内网, 监听授权流程
    Socket                  m_sListenInternal;  ///< 内网, 监听
    CFileLog                m_FileLog;          ///< 简单文本日志
    CEventHandlerPtr        m_MgrHandler;       ///< 控制台回调接口
    CNetworkPtr             m_NetworkPtr;       ///< 网络
    CCommonRoutinePtr       m_RoutinePtr;       ///< 例程处理
    MASTER_ADDR             m_ServerInfo;       ///< 本服务器信息
    SERVER_INFO             m_Server[PAKT_MAX - PAKT_MASTER];        ///< 服务器组统计数据, service+gate
    SVR_SERVICE_MAP         m_Service;          ///< 业务功能服务器信息
    SVR_GATE_MAP            m_Gate;             ///< 业务网关服务器信息
    RESULT_CHAIN            m_SortChain;        ///< 业务网关服务器排序结果
};

INLINE CMasterServer::CMasterServer(void)
: m_nStatus(STATUSS_NONE)
, m_nCenterLink(STATUSL_NONE)
, m_nMasterDBLink(STATUSL_NONE)
, m_nServerInfo(TRUE)
, m_nServerAck(FALSE)
, m_nSyncInfo(FALSE)
, m_nCommonEvent(FALSE)
, m_pConfig(nullptr)
, m_sConnectCenter(0)
, m_sConnectMasterDB(0)
, m_sListenAuthor(0)
, m_sListenInternal(0)
, m_FileLog(false)
{
}

INLINE CMasterServer::~CMasterServer(void)
{
}

INLINE CMasterServer::CMasterServer(const CMasterServer&)
: m_nStatus(STATUSS_NONE)
, m_nCenterLink(STATUSL_NONE)
, m_nMasterDBLink(STATUSL_NONE)
, m_nServerInfo(TRUE)
, m_nServerAck(FALSE)
, m_nSyncInfo(FALSE)
, m_nCommonEvent(FALSE)
, m_pConfig(nullptr)
, m_sConnectCenter(0)
, m_sConnectMasterDB(0)
, m_sListenAuthor(0)
, m_sListenInternal(0)
, m_FileLog(false)
{
}

INLINE CMasterServer& CMasterServer::operator=(const CMasterServer&)
{
    return (*this);
}

INLINE bool CMasterServer::OnTcpRecv(size_t, PTCP_PARAM)
{
    return false;
}

INLINE bool CMasterServer::OnTcpSend(UInt, Socket)
{
    return true;
}

INLINE bool CMasterServer::OnUdpRecv(size_t, PUDP_PARAM)
{
    return false;
}

INLINE bool CMasterServer::OnUdpSend(UInt, Socket)
{
    return true;
}

INLINE Socket_t CMasterServer::GetSocket(UInt uType)
{
    Socket_t sSocket = m_sListenInternal;
    switch (uType)
    {
    case PAKT_CENTER:
        {
            sSocket = m_sConnectCenter;
        }
        break;
    case PAKT_MASTERDB:
        {
            sSocket = m_sConnectMasterDB;
        }
        break;
    case PAKT_AUTHOR:
        {
            sSocket = m_sListenAuthor;
        }
        break;
    default:
        {
        }
    }
    return sSocket;
}

INLINE PSERVER_INFO CMasterServer::GetServerInfo(UInt uType)
{
    switch (uType)
    {
    case PAKT_SERVICE:
        {
            return (m_Server + (PAKT_SERVICE - PAKT_MASTER));
        }
        break;
    case PAKT_GATE:
        {
            return (m_Server + (PAKT_GATE - PAKT_MASTER));
        }
        break;
    default:
        {
        }
    }
    return &m_ServerInfo;
}

INLINE PSVR_COMMON_MAP CMasterServer::GetServerMap(UInt uType)
{
    if (uType == PAKT_SERVICE)
    {
        return (PSVR_COMMON_MAP)&m_Service;
    }
    else if (uType == PAKT_GATE)
    {
        return (PSVR_COMMON_MAP)&m_Gate;
    }
    return nullptr;
}

INLINE PRESULT_CHAIN CMasterServer::GetServerSort(UInt uType)
{
    if (uType == PAKT_GATE)
    {
        return &m_SortChain;
    }
    return nullptr;
}

INLINE CServerConfig& CMasterServer::GetConfig(void)
{
    return (*m_pConfig);
}

INLINE CFileLog& CMasterServer::GetFileLog(void)
{
    return m_FileLog;
}

INLINE CEventHandlerPtr& CMasterServer::GetMgrHandler(void)
{
    return m_MgrHandler;
}

INLINE CNetworkPtr& CMasterServer::GetNetworkPtr(void)
{
    return m_NetworkPtr;
}

template <typename MAP_REF, PAK_TYPE PakType>
INLINE bool CMasterServer::ServerLink(CNETLink* pLink, ULLong ullKey, MAP_REF& MapRef)
{
    PINDEX index = nullptr;
    // 1.获取信息
    typename MAP_REF::SVR_PAIR Pair;
    Pair.ullKey = ullKey;
    Pair.Value.Copy(pLink->GetServerStatus());
    assert(Pair.Value.usStatus == STATUSU_LINK);
    assert(pLink->CheckStream());
    Pair.Value.Addr(pLink->GetStream());
    {
        CSyncLockWaitScope scope(MapRef.SvrLock);
        typename MAP_REF::SVR_MAP_PAIR* pPair = MapRef.SvrMap.Find(ullKey);
        if (pPair == nullptr)
        {
            index = MapRef.SvrMap.Add(ullKey, Pair.Value);
            LOGV_INFO(m_FileLog, TF("[业务管理]服务器(type=%d)%p注册1, Id=%d"), PakType, ullKey, Pair.Value.usId);
        }
        else
        {
            Pair.Value.usStatus = pPair->m_V.usStatus;
        }
    }
    if (index != nullptr)
    {
        m_Server[PakType - PAKT_MASTER].Incr(pLink->GetServerStatus());
        (PakType == PAKT_SERVICE) ? m_ServerInfo.IncrOnline() : m_ServerInfo.IncrTotal(false);
        // 2.更新控制台
        m_MgrHandler->OnHandle(PAKE_LINK, reinterpret_cast<uintptr_t>(&Pair), PakType);
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[业务管理]服务器(type=%d)%p注册时存在异常状态=%d"), PakType, ullKey, Pair.Value.usStatus);
    }
    return (index != nullptr);
}

template <typename MAP_REF, PAK_TYPE PakType>
INLINE bool CMasterServer::ServerUpdate(CNETUpdate* pUpdate, ULLong ullKey, MAP_REF& MapRef)
{
    UShort usStatus = STATUSU_NONE;
    typename MAP_REF::SVR_PAIR Pair;
    Pair.ullKey = ullKey;
    {
        CSyncLockWaitScope scope(MapRef.SvrLock);
        typename MAP_REF::SVR_MAP_PAIR* pPair = MapRef.SvrMap.Find(ullKey);
        if ((pPair != nullptr) &&
            (pPair->m_V.usStatus > STATUSU_NONE) &&
            (pPair->m_V.usStatus < STATUSU_UNLINK))
        {
            Pair.Value.Copy(pPair->m_V);
            pPair->m_V.Copy(pUpdate->GetServerStatus());
        }
        else if (pPair != nullptr)
        {
            usStatus = pPair->m_V.usStatus;
        }
    }
    if (Pair.Value.usStatus > STATUSU_NONE)
    {
        m_Server[PakType - PAKT_MASTER].Diff(pUpdate->GetServerStatus(), Pair.Value);
        Pair.Value.Copy(pUpdate->GetServerStatus());
        m_MgrHandler->OnHandle(PAKE_UPDATE, reinterpret_cast<uintptr_t>(&Pair), PakType);// 更新控制台
        return true;
    }
    if (usStatus != STATUSU_NONE)
    {
        LOGV_WARN(m_FileLog, TF("[业务管理]服务器(type=%d)%p更新时存在异常状态=%d"), PakType, ullKey, usStatus);
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[业务管理]服务器(type=%d)%p更新时不存在"), PakType, ullKey);
    }
    return false;
}

template <typename MAP_REF, PAK_TYPE PakType>
INLINE bool CMasterServer::ServerUnlink(Socket sSocket, MAP_REF& MapRef, SERVER_UNLINK& su)
{
    // 2.更新控制台
    m_MgrHandler->OnHandle(PAKE_UNLINK, (uintptr_t)sSocket, PakType);
    SERVER_STATUS ss;
    {
        CSyncLockWaitScope scope(MapRef.SvrLock);
        typename MAP_REF::SVR_MAP_PAIR* pPair = MapRef.SvrMap.Find((ULLong)sSocket);
        if (pPair != nullptr)
        {
            ss = pPair->m_V;
            LOGV_INFO(m_FileLog, TF("[业务管理]服务器(type=%d)%p注销, Id=%d"), PakType, sSocket, ss.usId);
            if (PakType == PAKT_GATE)
            {
                MapRef.SvrMap.RemoveAt(reinterpret_cast<PINDEX>(pPair));
            }
            else
            {
                pPair->m_V.usStatus = STATUSU_UNLINK; // 需要判断是否业务管理改变状态
            }
        }
    }
    if (ss.usStatus > STATUSU_NONE)
    {
        m_Server[PakType - PAKT_MASTER].Decr(ss);
        (PakType == PAKT_SERVICE) ? m_ServerInfo.DecrOnline() : m_ServerInfo.DecrTotal(false);

        su.tiData.usType = (UShort)PakType;
        su.tiData.usId   = ss.usId;
        return true;
    }
    else
    {
        LOGV_WARN(m_FileLog, TF("[业务管理]服务器(type=%d)%p注销时不存在"), PakType, sSocket);
    }
    return false;
}

#endif // __MASTER_SERVER_IMP_H__
